package club.qweqwe.utils;

import club.qweqwe.annotation.*;
import club.qweqwe.exception.RequestException;
import club.qweqwe.model.form.Register;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class ReflectUtils {
    /**
     * 获得继承自父类的第一个泛型类型
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Class<T> getSuperGenericType(Class clazz){
        return getSuperClassGenricType(clazz, 0);
    }

    public static Class getSuperClassGenricType(Class clazz, int index){
        //获得继承自父类的泛型类型
        Type genType = clazz.getGenericSuperclass();
        //checked 若不是参数化类型
        if(!(genType instanceof ParameterizedType))
            return Object.class;

        Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
        //checked 获取的索引与参数数组长度
        if(index >= params.length || index < 0)
            return Object.class;

        //checked 若不是类类型
        if(!(params[index] instanceof Class))
            return Object.class;

        return (Class)params[index];
    }


    public static Map<String, String> getFormBeanRequestParams(Class clazz, HttpServletRequest request) throws RequestException {

        Field[] fields = clazz.getDeclaredFields();
        if (fields != null && fields.length > 0){
            HashMap<String, String> map = new HashMap<>();

            for (Field f :
                    fields) {
                String fieldName = f.getName();
                String[] paramVal = request.getParameterValues(fieldName);
                if(null == paramVal)
                    throw RequestException.REQUEST_ERROR_CODE_PARAMER;

                map.put(fieldName, paramVal[0]);
            }

            return map;
        }

        throw new IllegalArgumentException();
    }

    public static String getClassName(Class clazz){
        String clazzName = clazz.getName();
        ClassMeta meta = (ClassMeta) clazz.getDeclaredAnnotation(ClassMeta.class);
        if(meta != null){
            clazzName = meta.className();
        }

        return clazzName;
    }

    public static <T> boolean annotationChecker(Class clazz, Object obj) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            if (fields != null) {
                for (Field f :
                        fields) {
                    f.setAccessible(true);
                    Annotation[] annotations = f.getDeclaredAnnotations();
                    if (annotations != null) {
                        for (Annotation a :
                                annotations) {
                            if (a instanceof CharLimit) {
                                Character character = (Character) f.get(obj);
                                char[] limits = ((CharLimit) a).value();
                                boolean bFlag = false;
                                for (char c :
                                        limits) {
                                    if (character.equals(c))
                                        bFlag = true;
                                }

                                if(!bFlag)
                                    return false;

                            } else if (a instanceof IntegerLimit) {
                                Integer num = (Integer) f.get(obj);
                                int min = ((IntegerLimit) a).min();
                                int max = ((IntegerLimit) a).max();
                                if (num >= min && num <= max)
                                    continue;

                                return false;
                            } else if (a instanceof StrlenLimit) {
                                int len = ((String)f.get(obj)).length();

                                int min = ((StrlenLimit)a).min();
                                int max = ((StrlenLimit)a).max();

                                if(len < min || len > max)
                                    return false;

                            }else if(a instanceof NotNull){
                                try {
                                    f.get(obj);
                                }catch (NullPointerException e){
                                    return false;
                                }
                            }

                        }
                    }
                }
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
